-- VillagerM
-- Created by panyl
-- 村民模块

module("VillagerM", package.seeall);

local villagers = {};
local villagerBonus = {};
local bonusRule = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    villagers = {};
    villagerBonus = {};
    bonusRule = {};

    -- 转换下villager信息表
    local villager_CSV = get_villager_CSV();
    for i = 1, #villager_CSV do
        villagers[villager_CSV[i].class_id] = villager_CSV[i];
    end
    villager_CSV = {};

    -- 转换下villager_bonus信息表
    local villager_bonus_CSV = get_villager_bonus_CSV();
    for i = 1, #villager_bonus_CSV do
        local id   = villager_bonus_CSV[i].id;
        local rule = villager_bonus_CSV[i].rule;
        villagerBonus[id] = villager_bonus_CSV[i];

        bonusRule[rule] = bonusRule[rule] or {};
        table.insert(bonusRule[rule], villager_bonus_CSV[i]);
    end
    villager_bonus_CSV = {};

    -- 给排序一下
    for rule, bonus in pairs(bonusRule) do
        table.sort(bonus, function(a, b)
            return a.id < b.id;
        end);
    end
end

function init()
    loadCsv();
end

-- 检索
function query(classId, path)
    local m = villagers[classId];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 检索奖励
function queryBonus(id, path)
    local m = villagerBonus[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 抽取奖励id
function fetchBonusId(classId)
    local rule = query(classId, "bonus");
    local arr = table.deepcopy(bonusRule[rule]);
    local rand = DungeonM.getRandSeed("villager bonus");
    local sum = 0;
    local bonus;

    -- 根据权重抽取
    for index = 1, #arr do
        local dbase = arr[index]["dbase"];
        if (dbase["limited_gem"]) then
            local gemMaxTimes = dbase["limited_gem"];
            local buffId = dbase["buff_id"];
            -- 如果没有配置buff_id，或者次数超过了，权重置0
            if not buffId or BuffDataM.query("limited_gem", buffId) >= gemMaxTimes then
                arr[index]["ratio"] = 0;
            end
        end

        sum = sum + arr[index]["ratio"];
    end
    rand = rand % sum;
    sum = 0;
    for index = 1, #arr do
        sum = sum + arr[index]["ratio"];
        if (sum > rand) then
            -- 抽中限定奖励，需要统计次数
            if arr[index]["dbase"]["limited_gem"] then
                local buffId = arr[index]["dbase"]["buff_id"];
                local times = BuffDataM.query("limited_gem", buffId);

                BuffDataM.set("limited_gem", buffId, times + 1);
            end

            return arr[index]["id"];
        end
    end

    assert(0, "不应该走到这里。");
end

-- 抽取奖励
function calcBonus(bonusId)
    local bonus = queryBonus(bonusId, "bonus");

    if type(bonus) == "table" then
        return bonus;
    end

    if  type(bonus) == "string" and
        string.startWith(bonus, "formula_") then
        local formula = string.sub(bonus, string.len("formula_") + 1);
        return FormulaM.invoke(formula, bonusId);
    end

    -- 不应该走到这里
    assert(0, "村民奖励配置错误。");
end

-- 判断能否领取奖励
function canTakeBonus(pos)
    local grid = DungeonM.getGridByPos(pos);
    -- 如果不是村民
    if grid.type ~= GRID_TYPE_VILLAGER and grid.type ~= GRID_TYPE_VILLAGER_FIGHTER then
        trace("VillagerM", "格子%d不是村民。");
        return false;
    end

    -- 格子还未翻开
    if not grid:isOpened() then
        trace("VillagerM", "格子%d尚未翻开。");
        return false;
    end

    -- 如果村民已经失效了
    if grid.state == GRID_STATE_DISABLE then
        trace("VillagerM", "村民%s已经失效了。", query(grid.villager_id, "name"));
        return false;
    end

    -- 如果已经领取过奖励了
    if grid.type ~= GRID_TYPE_VILLAGER_FIGHTER and grid.took then
        return false;
    end

    local classId = grid.villager_id;
    local type = query(classId, "type");

    if type == VILLAGER_NORMAL then
        -- 普通村民，不需要什么条件
        return true;
    elseif type == VILLAGER_MONSTER_MISSION then
        -- 需要全部清怪之后才能领取
        return DungeonServiceM.isMonsterClear();
    elseif type == VILLAGER_FIGHTER then
        return #PropM.fetchProps(ME.user, "villager_fighter") > 0;
    else
        return false;
    end
end

-- 是否勇者村民
function isBraveVillager(classId)
    local dbase = query(classId, "dbase");
    if dbase ~= nil and dbase["villager_type"] == "brave" then
        return true;
    end

    return false;
end

-- 是否罗马村民
function isRomanVillager(classId)
    local dbase = query(classId, "dbase");
    if dbase ~= nil and dbase["villager_type"] == "roman" then
        return true;
    end

    return false;
end

-- 是否杂志村民
function isMagazineVillager(classId)
    local dbase = query(classId, "dbase");
    if dbase ~= nil and dbase["villager_type"] == "magazine" then
        return true;
    end

    return false;
end

-- 领取村民奖励
function takeBonus(pos)
    -- 判断
    if not canTakeBonus(pos) then
        return false;
    end

    local grid = DungeonM.getGridByPos(pos);
    local classId = grid.villager_id;
    local bonusId = fetchBonusId(classId);
    local arr = calcBonus(bonusId);

    trace("VillagerM", "领取村民%s的奖励。", query(classId, "name"));

    -- 斗士村民，或者没有雅典娜
    if grid.type == GRID_TYPE_VILLAGER_FIGHTER or
        #PropM.fetchProps(ME.user, "villager_fighter") <= 0 then
        -- 无效了
        grid:changeState(GRID_STATE_DISABLE);
    end

    -- 标记已经领取过奖励了
    grid.took = 1;

    -- 次数+1
    if isBraveVillager(classId) then
        local times = ME.user.dbase:query("bravetimes", 0);
        ME.user.dbase:set("bravetimes", times + 1);
    end

    -- 杂志村民，记录次数
    if isMagazineVillager(classId) then
        local times = ME.user.dbase:query("magazines", 0);
        ME.user.dbase:set("magazines", times + 1);
    end

    for _, bonus in pairs(arr) do
        BonusM.doBonus(bonus, "villager_bonus");
    end

    EventMgr.fire(event.VILLAGER_BONUS, {["pos"] = pos, ["bonus"] = arr, });

    -- 冒险者专属发动特效
    local prop = PropM.combine(ME.user, "villager_chest", 1);
    if prop[3] > 0 and grid.type == GRID_TYPE_VILLAGER then
        -- 触发特技发动事件
        EventMgr.fire(event.SPECIAL_SKILL_TRIGGER, { propId = prop[1], key = prop[2] });
    end

    -- 雅典娜专属发动特效
    local prop = PropM.combine(ME.user, "slime_strengthen", "saint");
    if prop[3] > 0 and grid.type == GRID_TYPE_VILLAGER_FIGHTER then
        -- 触发特技发动事件
        EventMgr.fire(event.SPECIAL_SKILL_TRIGGER, { propId = prop[1], key = prop[2] });
    end

    -- 通知建筑事件完成
    EventMgr.fire(event.BUILDING_EVENT_DONE, {["pos"] = pos})

    -- 记录数量转化装备
    if isRomanVillager(classId) then
        local props = PropM.fetchProps(ME.user, "arm_villager_upgrade");
        for _, prop in ipairs(props) do
            PropM.trigger(ME.user, prop[1], prop[2]);
        end
    end

    -- 返回奖励ID及内容，用于提示
    return {[bonusId] = arr};
end

-- 获取奖励描述
function getBonusDesc(bonusInfo)
    local bonusId = table.keys(bonusInfo)[1];
    local info = queryBonus(bonusId);
    local desc = getLocStr("get_villager_treasure" .. info.desc_type);

    if info.desc_type == 8 then
        local bravetimes = ME.user.dbase:query("bravetimes", 0);
        desc = string.format(desc, bravetimes);
    end

    -- 获取奖励信息
    local bonus = bonusInfo[bonusId];
    local bonusDesc = "";
    local seperator = "";

    for i, v in pairs(bonus) do
        -- 拼接奖励信息
        if i ~= 1 then
            seperator = getLocStr("seperator");
        end

        if v[1] == 1 then
            -- 道具奖励
            if bonusId == 140 then
                -- 道具名称过长，换行处理
                bonusDesc = bonusDesc .. "\n" .. string.format("%s+%d", ItemM.query(v[2], "name"), v[3]);
            else
                -- 正常使用顿号间隔
                bonusDesc = bonusDesc .. seperator .. string.format("%s+%d", ItemM.query(v[2], "name"), v[3]);
            end
        elseif v[1] == 2 then
            -- 属性奖励
            if v[2] == "bine_attrib" then
                -- 魔藤需要额外处理
                bonusDesc = bonusDesc .. seperator .. getLocStr("get_villager_treasure11");
            else
                if i == 3 then
                    bonusDesc = bonusDesc .. seperator .. string.format("\n%s+%d", FieldsM.getFieldName(v[2]), v[3]);
                else
                    bonusDesc = bonusDesc .. seperator .. string.format("%s+%d", FieldsM.getFieldName(v[2]), v[3]);
                end
            end
        end
    end

    return desc .. "\n" .. bonusDesc;
end

-- 能否武装
function canArm(pos)
    local grid = DungeonM.getGridByPos(pos);

    -- 状态
    if grid.state == GRID_STATE_DISABLE then
        return false;
    end

    -- 如果是斗士村民
    if grid.type == GRID_TYPE_VILLAGER_FIGHTER then
        return true;
    end

    -- 应该是普通村民
    if grid.type ~= GRID_TYPE_VILLAGER then
        return false;
    end

    -- 如果还未领取普通奖励
    if not grid.took then
        return false;
    end

    -- 如果没有专门的属性
    if #PropM.fetchProps(ME.user, "villager_fighter") <= 0 then
        return false;
    end

    return true;
end

-- 武装村民
function doArm(pos)
    if not canArm(pos) then
        return false;
    end

    local grid = DungeonM.getGridByPos(pos);

    -- 先设置状态
    grid.state = GRID_STATE_DISABLE;

    local rule = "bonus_fighter";

    -- 如果是勇者村民
    if isBraveVillager(grid.villager_id) then
        rule = "brave_fighter";
    end

    local bonusId = bonusRule[rule][1]["id"];
    local arr = calcBonus(bonusId);

    for _, bonus in pairs(arr) do
        BonusM.doBonus(bonus, "arm_villager");
    end

    EventMgr.fire(event.VILLAGER_BONUS, {["pos"] = pos, ["bonus"] = arr, });

    -- 通知建筑事件完成
    EventMgr.fire(event.BUILDING_EVENT_DONE, {["pos"] = pos})

    -- 记录数量转化装备
    local props = PropM.fetchProps(ME.user, "arm_villager_upgrade");
    for _, prop in ipairs(props) do
        PropM.trigger(ME.user, prop[1], prop[2]);
    end

    return true;
end
